use std::{collections::HashMap, mem::MaybeUninit, sync::Once};

use ylong_runtime::sync::Mutex;

use crate::common::hdc_error::{HdcError, HdcErrorKind};

use super::{usb::usb_stub::UsbStub, Stub};

pub enum StubInterface {
    UsbStub(UsbStub),
}

struct SessionManager {
    map: HashMap<String, StubInterface>,
}

impl SessionManager {
    pub fn get_instance() -> &'static Mutex<SessionManager> {
        static mut SESSION_MANAGER_INSTANCE: MaybeUninit<Mutex<SessionManager>> = MaybeUninit::uninit();
        static ONCE: Once = Once::new();
        unsafe {
            ONCE.call_once(|| {
                SESSION_MANAGER_INSTANCE = MaybeUninit::new(Mutex::new(SessionManager { map: HashMap::new() }))
            });
            &*SESSION_MANAGER_INSTANCE.as_ptr()
        }
    }

    fn insert(&mut self, connect_key: &str, stub: StubInterface) -> Option<StubInterface> {
        self.map.insert(connect_key.to_owned(), stub)
    }

    fn remove(&mut self, connect_key: &String) {
        self.map.remove(connect_key);
    }

    fn contains_key(&self, connect_key: &String) -> bool {
        self.map.contains_key(connect_key)
    }

    async fn get_stub(&mut self, connect_key: &str) -> Option<Stub> {
        let session = if connect_key == "any" && self.map.len() == 1 {
            self.map.values_mut().next()
        } else {
            self.map.get_mut(connect_key)
        };

        match session {
            Some(stub) => match stub {
                StubInterface::UsbStub(usb_stub) => {
                    let stub = usb_stub.get_session().await;
                    Some(stub)
                }
            },
            None => None,
        }
    }
}

pub async fn add_session(connect_key: &str, stub: StubInterface) {
    let mut session_manager = SessionManager::get_instance().lock().await;
    session_manager.insert(connect_key, stub);
}

#[allow(unused)]
pub async fn close_session(connect_key: &String) {
    let mut session_manager = SessionManager::get_instance().lock().await;
    session_manager.remove(connect_key);
}

pub async fn contains_key(connect_key: &String) -> bool {
    let session_manager = SessionManager::get_instance().lock().await;
    session_manager.contains_key(connect_key)
}

pub async fn get_stub(connect_key: &str) -> Result<Stub, HdcError> {
    let mut session_manager = SessionManager::get_instance().lock().await;
    match session_manager.get_stub(connect_key).await {
        Some(session) => Ok(session),
        None => {
            let msg = format!("Get stub None, {connect_key}");
            log::error!("{msg}");
            Err(HdcError::new(HdcErrorKind::HdcNotFound, msg))
        }
    }
}
